﻿using System;

//anur 
//for dllimport
using System.Runtime.InteropServices;


using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;


namespace WindowsGame1
{

    

    /// <summary>
    /// This is the main type for your game 
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        bool m_IsCursorClipped=false;
        //anur
        //Structure for ClipCursor
        //lolololo kl
        //anur LOLOLOLOLO fuk
        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }

        //anur
        //Limits mouse movement (to our window in our case)
        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        public static extern bool ClipCursor(ref RECT rcClip);

        //Get rect for clip
        [DllImport("user32.dll")]
        public static extern int GetWindowRect(IntPtr hwnd, ref RECT lpRect);

        
        [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
        public static extern IntPtr GetDesktopWindow();



        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        //anur
        //font for version text
        SpriteFont FontVer;
        //Sprite for mouse cursor
        Texture2D cursorTex;


        GObject cannon;
      //  GObject enemy;



        //anur 
        //player speed, 100 pixels a second if we multiply it by milliseconds passed from last update
        const float m_PlayerSpeed = 0.1F;


        /// <summary>
        /// fess
        /// array for maximum cannonballs number
        /// </summary>
        const int maxcannonballs = 5;
        GObject[] cannonballs;


        /// <summary>
        /// fess
        /// description of mouse state
        /// </summary>
        /// 
        MouseState prev = Mouse.GetState();


        /// <summary>
        /// fess
        /// enemies randomizer
        /// as constants
        /// </summary>

        const int maxEnemies = 3;
        const float maxEnemiesHight = 0.1f;
        const float minEnemiesHight = 0.5f;
        const float maxEnemiesVelocity = 5.0f;
        const float minEnemiesVelocity = 1.0f;
        GObject[] enemies;

        Random VBR = new Random();


        public Game1()
        {
            //anur
            //resize window
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferHeight = 768;
            graphics.PreferredBackBufferWidth = 1024;



            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here


            base.Initialize();

            //anur
            this.Window.AllowUserResizing = true;
            this.Window.Title = "Flesstohanurmius";
            this.IsMouseVisible = false;

        }


        protected string GetVersion()
        {
            string version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
            return version;
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {



            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            cannon = new GObject(Content.Load<Texture2D>("sprite\\cannon"));

            cannon.position = new Vector2(
                120, graphics.GraphicsDevice.Viewport.Height - 240);


  //          enemy = new GObject(Content.Load<Texture2D>("sprite\\enemy"));
//
   //         enemy.position = new Vector2(
   //             240, graphics.GraphicsDevice.Viewport.Height - 160);

  

         /// fess
         /// cannonballs description and limiter
         /// 


            cannonballs = new GObject[maxcannonballs];

            for (int i = 0; i < maxcannonballs; i++)
            {
                cannonballs[i] = new GObject(
                    Content.Load<Texture2D>("sprite\\cannonball"));
            }

            enemies = new GObject[maxEnemies];
            for (int i = 0; i < maxEnemies; i++)
            {
                enemies[i] = new GObject(Content.Load<Texture2D>("sprite\\enemy"));
            }



            //anur
            //font for version text
            FontVer = Content.Load<SpriteFont>("SpriteFontVersion");

            //anur
            //Cursor sprite
            cursorTex = Content.Load<Texture2D>("sprite\\cursor");
            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
            UnClipCursor();
        }







        //anur
        // clip - unclip mouse to our window 
        protected void ClipCursor()
        {
            RECT rc = new RECT();
            //Rectangle myrc = GraphicsDevice.Viewport.Bounds;
            Rectangle myrc = this.Window.ClientBounds;
            rc.bottom = myrc.Bottom;
            rc.top = myrc.Top;
            rc.left = myrc.Left;
            rc.right = myrc.Right;
            ClipCursor(ref rc);
        }

        /// <summary>
        /// 
        /// </summary>
        protected void UnClipCursor()
        {
            RECT rc = new RECT();
            rc.left = 0;
            rc.top = 0;
            rc.right = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
            rc.bottom = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
            ClipCursor(ref rc);
        }



        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        /// 
        protected override void Update(GameTime gameTime)
        {
            var kb = Keyboard.GetState();
            MouseState ms = Mouse.GetState();
            Vector2 mpos;
            mpos.X=ms.X;
            mpos.Y=ms.Y;






            // anur
            // kill Cannonballs if they fly out of screen
            foreach (var x in cannonballs)
            {
                if ( x.alive && 
                     (
                          x.position.Y > graphics.GraphicsDevice.Viewport.Height
                       || x.position.Y < 0
                       || x.position.X > graphics.GraphicsDevice.Viewport.Width
                       || x.position.X < 0)
                     )
                {
                    x.alive = false;
                }
            }


            /// fess
            /// cannonballs positions & mouse click
            /// upd. 
            /// added "click moment" tracking
            /// 

            if ((prev.LeftButton == ButtonState.Released) && (ms.LeftButton == ButtonState.Pressed)) 
            {
                foreach (var x in cannonballs)
                {
                    if (!x.alive)
                    {
                        x.alive = true;
                        x.position = cannon.position;
                        x.velocity = 10.0f*new Vector2((float) Math.Cos(cannon.rotation),(float) Math.Sin(cannon.rotation));
                        break;
                    }
                }

            }


           

        

            foreach (var x in cannonballs)
            {
                if (x.alive)
                {
                    x.position += x.velocity;
                }
            }




            //anur
            //if we are in focus
            if (IsActive)
            {
                //ctrl allows moving anywhere
                if ( kb.IsKeyDown(Keys.LeftControl) && m_IsCursorClipped)
                {
                    UnClipCursor();
                    m_IsCursorClipped = false;
                    this.IsMouseVisible = true;
                }



                if (!kb.IsKeyDown(Keys.LeftControl) && !m_IsCursorClipped)
                {
                    ClipCursor();
                    m_IsCursorClipped = true;
                    this.IsMouseVisible = false;
                }


            }

            //not in focus - free mouse
            else
            {
                UnClipCursor();
                m_IsCursorClipped = false;
            }


             




            // Allows the game to exit
            if (kb.IsKeyDown(Keys.Q))
            {
                this.Exit();
            }




            //anur
            //player Movement. Multiply time passed from last update by player speed
            if (kb.IsKeyDown(Keys.W))
            {
                cannon.position.Y -= (float)gameTime.ElapsedGameTime.TotalMilliseconds * m_PlayerSpeed;
            }
            if (kb.IsKeyDown(Keys.S))
            {
                cannon.position.Y += (float)gameTime.ElapsedGameTime.TotalMilliseconds * m_PlayerSpeed;
            }
            if (kb.IsKeyDown(Keys.D))
            {
                cannon.position.X += (float)gameTime.ElapsedGameTime.TotalMilliseconds * m_PlayerSpeed;
            }
            if (kb.IsKeyDown(Keys.A))
            {
                cannon.position.X -= (float)gameTime.ElapsedGameTime.TotalMilliseconds * m_PlayerSpeed;
            }   






            //anur
            //Player rotation.

            
            //subtract player coords to get vector from player to mouse
            Vector2 direction;
            direction.X = ms.X - cannon.position.X;
            direction.Y = ms.Y - cannon.position.Y;
            
            //get angle
            float rot = (float)Math.Atan2(direction.Y, direction.X);
            
            //rotate
            cannon.rotation = rot;

            prev = ms;

            updateenemies();

            base.Update(gameTime);
        }


        /// fess
        /// description of enemies movement
        /// 

        public void updateenemies()
        {
            foreach (GObject enemy in enemies)
            {
                if (enemy.alive)
                {
                    enemy.position += enemy.velocity;
                    if (  enemy.position.Y > graphics.GraphicsDevice.Viewport.Height
                       || enemy.position.Y < 0
                       || enemy.position.X > graphics.GraphicsDevice.Viewport.Width
                       || enemy.position.X < 0)
                    {
                        enemy.alive = false;
                    }

                    enemy.velocity = new Vector2(((float)VBR.NextDouble() - 0.5F) + enemy.velocity.X,( (float)VBR.NextDouble() - 0.5F) + enemy.velocity.Y);
                }
                else
                {
                    enemy.alive = true;

                    enemy.position = new Vector2( 
                        550,
                        // );
                        MathHelper.Lerp(
                    (float)graphics.GraphicsDevice.Viewport.Width * minEnemiesHight,
                        (float)200 * maxEnemiesHight,
                       (float)VBR.NextDouble()));

                    enemy.velocity = new Vector2(
                        (float)VBR.NextDouble() - 0.5F,
                            (float)VBR.NextDouble() - 0.5F);


                }
            }


        }
        
        


        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            MouseState ms = Mouse.GetState();
            var kb = Keyboard.GetState();


            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend); 

            //anur
            //draw mouse cursor TODO (too slow)
            if (IsActive)
            {
                Vector2 mpos;
                mpos.X = ms.X - cursorTex.Bounds.Width / 2;
                mpos.Y = ms.Y - cursorTex.Bounds.Height / 2;
                spriteBatch.Draw(cursorTex, mpos, Color.White);
            }





            spriteBatch.Draw(cannon.sprite,
                cannon.position, null, Color.White,
                cannon.rotation,
                cannon.center, 1.0f,
                SpriteEffects.None, 0);

      //      spriteBatch.Draw(enemy.sprite,
     //           enemy.position, null, Color.White,
      //          enemy.rotation,
      //          enemy.center, 1.0f,
      //          SpriteEffects.None, 0);

            /// fess 
            /// cannonballs drawing

            foreach (GObject ball in cannonballs)
            {
                if (ball.alive)
                {
                    spriteBatch.Draw(ball.sprite, ball.position, Color.Yellow);
                }
            }
// 
//             foreach (GObject ob in m_gobjects)
//             {
//                 ob.tratata;
//             }
            
            /// fess
            /// enemies drawing
            /// 

            foreach (GObject enemy in enemies)
            {
                if (enemy.alive)
                {
                    spriteBatch.Draw(enemy.sprite, enemy.position, Color.White);
                }
            }

            //anur
            //show version
            if (kb.IsKeyDown(Keys.V))
            {
                Vector2 pos = new Vector2(0,0); 
                spriteBatch.DrawString(FontVer, GetVersion(), pos, Color.Blue );
            }

            spriteBatch.End();

            // TODO: Add your drawing code here

            base.Draw(gameTime);
        }
    }
}
